1 /** 2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved. 3 License: MPL-2 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 This Source Code Form is subject to the terms of the Mozilla Public License, 7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain 8 one at http://mozilla.org/MPL/2.0/. 9 10 This is a handy range to interate over either all files from the user OR all 11 files in a compilation database. 12 */ 13 module code_checker.compile_db.user_filerange; 14 15 import logger = std.experimental.logger; 16 17 import code_checker.compile_db : CompileCommandFilter, CompileCommandDB, 18 parseFlag, SearchResult; 19 import code_checker.types : FileName, AbsolutePath; 20 21 @safe: 22 23 struct UserFileRange { 24 import std.typecons : Nullable; 25 import code_checker.compile_db : SearchResult; 26 27 enum RangeOver { 28 inFiles, 29 database 30 } 31 32 this(CompileCommandDB db, string[] in_files, string[] cflags, 33 const CompileCommandFilter ccFilter) { 34 this.db = db; 35 this.cflags = cflags; 36 this.ccFilter = ccFilter; 37 this.inFiles = in_files; 38 39 if (in_files.length == 0) { 40 kind = RangeOver.database; 41 } else { 42 kind = RangeOver.inFiles; 43 } 44 } 45 46 const RangeOver kind; 47 CompileCommandDB db; 48 string[] inFiles; 49 string[] cflags; 50 const CompileCommandFilter ccFilter; 51 52 Nullable!SearchResult front() { 53 assert(!empty, "Can't get front of an empty range"); 54 55 Nullable!SearchResult curr; 56 57 final switch (kind) { 58 case RangeOver.inFiles: 59 if (db.length > 0) { 60 curr = db.findFlags(FileName(inFiles[0]), cflags, ccFilter); 61 } else { 62 curr = SearchResult(cflags.dup, AbsolutePath(FileName(inFiles[0]))); 63 } 64 break; 65 case RangeOver.database: 66 import std.array : appender; 67 68 auto tmp = db.payload[0]; 69 auto flags = appender!(string[])(); 70 flags.put(cflags); 71 flags.put(tmp.parseFlag(ccFilter)); 72 curr = SearchResult(flags.data, tmp.absoluteFile); 73 break; 74 } 75 76 return curr; 77 } 78 79 void popFront() { 80 assert(!empty, "Can't pop front of an empty range"); 81 82 final switch (kind) { 83 case RangeOver.inFiles: 84 inFiles = inFiles[1 .. $]; 85 break; 86 case RangeOver.database: 87 db.payload = db.payload[1 .. $]; 88 break; 89 } 90 } 91 92 bool empty() @safe pure nothrow const @nogc { 93 final switch (kind) { 94 case RangeOver.inFiles: 95 return inFiles.length == 0; 96 case RangeOver.database: 97 return db.length == 0; 98 } 99 } 100 101 size_t length() @safe pure nothrow const @nogc { 102 final switch (kind) { 103 case RangeOver.inFiles: 104 return inFiles.length; 105 case RangeOver.database: 106 return db.length; 107 } 108 } 109 } 110 111 private: 112 113 import std.typecons : Nullable; 114 115 /// Find flags for fname by searching in the compilation DB. 116 Nullable!SearchResult findFlags(ref CompileCommandDB compdb, FileName fname, 117 const string[] flags, ref const CompileCommandFilter flag_filter) { 118 import std.file : exists; 119 import std.path : baseName; 120 import std..string : join; 121 122 import code_checker.compile_db : appendOrError; 123 124 typeof(return) rval; 125 126 auto db_search_result = compdb.appendOrError(flags, fname, flag_filter); 127 if (!db_search_result.isNull) { 128 rval = SearchResult(db_search_result.cflags, db_search_result.absoluteFile); 129 logger.trace("Compiler flags: ", rval.cflags.join(" ")); 130 return rval; 131 } 132 133 logger.error("Unable to find any compiler flags for: ", fname); 134 return rval; 135 }